// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/renderer/media/audio_renderer_mixer_manager.h"

#include <memory>

#include "base/bind.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "build/build_config.h"
#include "content/renderer/media/audio_renderer_sink_cache.h"
#include "media/audio/audio_device_description.h"
#include "media/base/audio_parameters.h"
#include "media/base/audio_renderer_mixer.h"
#include "media/base/audio_renderer_mixer_input.h"
#include "media/base/fake_audio_render_callback.h"
#include "media/base/mock_audio_renderer_sink.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"

namespace content {

namespace {
    const int kBitsPerChannel = 16;
    const int kSampleRate = 48000;
    const int kBufferSize = 8192;
    const int kHardwareSampleRate = 44100;
    const int kHardwareBufferSize = 128;
    const media::ChannelLayout kChannelLayout = media::CHANNEL_LAYOUT_STEREO;
    const media::ChannelLayout kAnotherChannelLayout = media::CHANNEL_LAYOUT_2_1;
    const char* const kDefaultDeviceId = media::AudioDeviceDescription::kDefaultDeviceId;
    const char kAnotherDeviceId[] = "another-device-id";
    const char kMatchedDeviceId[] = "matched-device-id";
    const char kNonexistentDeviceId[] = "nonexistent-device-id";

    const int kRenderFrameId = 124;
    const int kAnotherRenderFrameId = 678;
} // namespace;

using media::AudioLatency;
using media::AudioParameters;

class FakeAudioRendererSinkCache : public AudioRendererSinkCache {
public:
    using GetSinkCallback = base::Callback<scoped_refptr<media::AudioRendererSink>(
        int render_frame_id,
        int session_id,
        const std::string& device_id,
        const url::Origin& security_origin)>;

    using ReleaseSinkCallback = base::Callback<void(const media::AudioRendererSink*)>;

    FakeAudioRendererSinkCache(const GetSinkCallback& get_sink_cb,
        const ReleaseSinkCallback& release_sink_cb)
        : get_sink_cb_(get_sink_cb)
        , release_sink_cb_(release_sink_cb)
    {
    }

    media::OutputDeviceInfo GetSinkInfo(
        int source_render_frame_id,
        int session_id,
        const std::string& device_id,
        const url::Origin& security_origin) final
    {
        return get_sink_cb_
            .Run(source_render_frame_id, session_id, device_id, security_origin)
            ->GetOutputDeviceInfo();
    }

    scoped_refptr<media::AudioRendererSink> GetSink(
        int source_render_frame_id,
        const std::string& device_id,
        const url::Origin& security_origin) final
    {
        return get_sink_cb_.Run(source_render_frame_id, 0, device_id,
            security_origin);
    }

    void ReleaseSink(const media::AudioRendererSink* sink) final
    {
        release_sink_cb_.Run(sink);
    }

private:
    GetSinkCallback get_sink_cb_;
    ReleaseSinkCallback release_sink_cb_;
};

class AudioRendererMixerManagerTest : public testing::Test {
public:
    AudioRendererMixerManagerTest()
        : manager_(new AudioRendererMixerManager(
            std::unique_ptr<AudioRendererSinkCache>(
                new FakeAudioRendererSinkCache(
                    base::Bind(&AudioRendererMixerManagerTest::GetSinkPtr,
                        base::Unretained(this)),
                    base::Bind(&AudioRendererMixerManagerTest::ReleaseSinkPtr,
                        base::Unretained(this))))))
        , mock_sink_(new media::MockAudioRendererSink(
              kDefaultDeviceId,
              media::OUTPUT_DEVICE_STATUS_OK,
              AudioParameters(AudioParameters::AUDIO_PCM_LINEAR,
                  kChannelLayout,
                  kHardwareSampleRate,
                  kBitsPerChannel,
                  kHardwareBufferSize)))
        , mock_sink_no_device_(new media::MockAudioRendererSink(
              kNonexistentDeviceId,
              media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND))
        , mock_sink_matched_device_(
              new media::MockAudioRendererSink(kMatchedDeviceId,
                  media::OUTPUT_DEVICE_STATUS_OK))
        , kSecurityOrigin2(GURL("http://localhost"))
    {
    }

    media::AudioRendererMixer* GetMixer(
        int source_render_frame_id,
        const media::AudioParameters& params,
        AudioLatency::LatencyType latency,
        const std::string& device_id,
        const url::Origin& security_origin,
        media::OutputDeviceStatus* device_status)
    {
        return manager_->GetMixer(source_render_frame_id, params, latency,
            device_id, security_origin, device_status);
    }

    void ReturnMixer(media::AudioRendererMixer* mixer)
    {
        return manager_->ReturnMixer(mixer);
    }

    // Number of instantiated mixers.
    int mixer_count()
    {
        return manager_->mixers_.size();
    }

protected:
    scoped_refptr<media::AudioRendererSink> GetSinkPtr(
        int source_render_frame_id,
        int session_id,
        const std::string& device_id,
        const url::Origin& security_origin)
    {
        if ((device_id == kDefaultDeviceId) || (device_id == kAnotherDeviceId)) {
            // We don't care about separate sinks for these devices.
            return mock_sink_;
        }
        if (device_id == kNonexistentDeviceId)
            return mock_sink_no_device_;
        if (device_id.empty()) {
            // The sink used to get device ID from session ID if it's not empty
            return session_id ? mock_sink_matched_device_ : mock_sink_;
        }
        if (device_id == kMatchedDeviceId)
            return mock_sink_matched_device_;

        NOTREACHED();
        return nullptr;
    }

    MOCK_METHOD1(ReleaseSinkPtr, void(const media::AudioRendererSink*));

    std::unique_ptr<AudioRendererMixerManager> manager_;

    scoped_refptr<media::MockAudioRendererSink> mock_sink_;
    scoped_refptr<media::MockAudioRendererSink> mock_sink_no_device_;
    scoped_refptr<media::MockAudioRendererSink> mock_sink_matched_device_;

    // To avoid global/static non-POD constants.
    const url::Origin kSecurityOrigin;
    const url::Origin kSecurityOrigin2;

private:
    DISALLOW_COPY_AND_ASSIGN(AudioRendererMixerManagerTest);
};

// Verify GetMixer() and ReturnMixer() both work as expected; particularly with
// respect to the explicit ref counting done.
TEST_F(AudioRendererMixerManagerTest, GetReturnMixer)
{
    // Since we're testing two different sets of parameters, we expect
    // AudioRendererMixerManager to call Start and Stop on our mock twice.
    EXPECT_CALL(*mock_sink_.get(), Start()).Times(2);
    EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2);

    // We expect 2 mixers to be created; each of them should release the sink.
    EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(2);

    // There should be no mixers outstanding to start with.
    EXPECT_EQ(0, mixer_count());

    media::AudioParameters params1(media::AudioParameters::AUDIO_PCM_LINEAR,
        kChannelLayout, kSampleRate, kBitsPerChannel,
        kBufferSize);

    media::AudioRendererMixer* mixer1 = GetMixer(kRenderFrameId, params1, AudioLatency::LATENCY_PLAYBACK,
        kDefaultDeviceId, kSecurityOrigin, nullptr);
    ASSERT_TRUE(mixer1);
    EXPECT_EQ(1, mixer_count());

    // The same parameters should return the same mixer1.
    EXPECT_EQ(mixer1,
        GetMixer(kRenderFrameId, params1, AudioLatency::LATENCY_PLAYBACK,
            kDefaultDeviceId, kSecurityOrigin, nullptr));
    EXPECT_EQ(1, mixer_count());

    // Return the extra mixer we just acquired.
    ReturnMixer(mixer1);
    EXPECT_EQ(1, mixer_count());

    media::AudioParameters params2(
        AudioParameters::AUDIO_PCM_LINEAR, kAnotherChannelLayout, kSampleRate * 2,
        kBitsPerChannel, kBufferSize * 2);
    media::AudioRendererMixer* mixer2 = GetMixer(kRenderFrameId, params2, AudioLatency::LATENCY_PLAYBACK,
        kDefaultDeviceId, kSecurityOrigin, nullptr);
    ASSERT_TRUE(mixer2);
    EXPECT_EQ(2, mixer_count());

    // Different parameters should result in a different mixer1.
    EXPECT_NE(mixer1, mixer2);

    // Return both outstanding mixers.
    ReturnMixer(mixer1);
    EXPECT_EQ(1, mixer_count());
    ReturnMixer(mixer2);
    EXPECT_EQ(0, mixer_count());
}

// Verify GetMixer() correctly deduplicates mixer with irrelevant AudioParameter
// differences.
TEST_F(AudioRendererMixerManagerTest, MixerReuse)
{
    EXPECT_CALL(*mock_sink_.get(), Start()).Times(2);
    EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2);
    EXPECT_EQ(mixer_count(), 0);

    // We expect 2 mixers to be created; each of them should release the sink.
    EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(2);

    media::AudioParameters params1(AudioParameters::AUDIO_PCM_LINEAR,
        kChannelLayout,
        kSampleRate,
        kBitsPerChannel,
        kBufferSize);
    media::AudioRendererMixer* mixer1 = GetMixer(kRenderFrameId, params1, AudioLatency::LATENCY_PLAYBACK,
        kDefaultDeviceId, kSecurityOrigin, nullptr);
    ASSERT_TRUE(mixer1);
    EXPECT_EQ(1, mixer_count());

    // Different sample rates, formats, bit depths, and buffer sizes should not
    // result in a different mixer.
    media::AudioParameters params2(AudioParameters::AUDIO_PCM_LOW_LATENCY,
        kChannelLayout,
        kSampleRate * 2,
        kBitsPerChannel * 2,
        kBufferSize * 2);
    media::AudioRendererMixer* mixer2 = GetMixer(kRenderFrameId, params2, AudioLatency::LATENCY_PLAYBACK,
        kDefaultDeviceId, kSecurityOrigin, nullptr);
    EXPECT_EQ(mixer1, mixer2);
    EXPECT_EQ(1, mixer_count());
    ReturnMixer(mixer2);
    EXPECT_EQ(1, mixer_count());

    // Modify some parameters that do matter: channel layout
    media::AudioParameters params3(AudioParameters::AUDIO_PCM_LOW_LATENCY,
        kAnotherChannelLayout,
        kSampleRate,
        kBitsPerChannel,
        kBufferSize);
    ASSERT_NE(params3.channel_layout(), params1.channel_layout());
    media::AudioRendererMixer* mixer3 = GetMixer(kRenderFrameId, params3, AudioLatency::LATENCY_PLAYBACK,
        kDefaultDeviceId, kSecurityOrigin, nullptr);
    EXPECT_NE(mixer1, mixer3);
    EXPECT_EQ(2, mixer_count());
    ReturnMixer(mixer3);
    EXPECT_EQ(1, mixer_count());

    // Return final mixer.
    ReturnMixer(mixer1);
    EXPECT_EQ(0, mixer_count());
}

// Verify CreateInput() provides AudioRendererMixerInput with the appropriate
// callbacks and they are working as expected.  Also, verify that separate
// mixers are created for separate RenderFrames, even though the
// AudioParameters are the same.
TEST_F(AudioRendererMixerManagerTest, CreateInput)
{
    // Expect AudioRendererMixerManager to call Start and Stop on our mock twice
    // each.  Note: Under normal conditions, each mixer would get its own sink!
    EXPECT_CALL(*mock_sink_.get(), Start()).Times(2);
    EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2);

    // We expect 2 mixers to be created; each of them should release the sink.
    EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(2);

    media::AudioParameters params(
        AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate,
        kBitsPerChannel, kBufferSize);

    // Create two mixer inputs and ensure this doesn't instantiate any mixers yet.
    EXPECT_EQ(0, mixer_count());
    media::FakeAudioRenderCallback callback(0, kSampleRate);
    scoped_refptr<media::AudioRendererMixerInput> input(
        manager_->CreateInput(kRenderFrameId, 0, kDefaultDeviceId,
            kSecurityOrigin, AudioLatency::LATENCY_PLAYBACK));
    input->Initialize(params, &callback);
    EXPECT_EQ(0, mixer_count());
    media::FakeAudioRenderCallback another_callback(1, kSampleRate);
    scoped_refptr<media::AudioRendererMixerInput> another_input(
        manager_->CreateInput(kAnotherRenderFrameId, 0, kDefaultDeviceId,
            kSecurityOrigin, AudioLatency::LATENCY_PLAYBACK));
    another_input->Initialize(params, &another_callback);
    EXPECT_EQ(0, mixer_count());

    // Implicitly test that AudioRendererMixerInput was provided with the expected
    // callbacks needed to acquire an AudioRendererMixer and return it.
    input->Start();
    EXPECT_EQ(1, mixer_count());
    another_input->Start();
    EXPECT_EQ(2, mixer_count());

    // Destroying the inputs should destroy the mixers.
    input->Stop();
    input = nullptr;
    EXPECT_EQ(1, mixer_count());
    another_input->Stop();
    another_input = nullptr;
    EXPECT_EQ(0, mixer_count());
}

// Verify CreateInput() provided with session id creates AudioRendererMixerInput
// with the appropriate callbacks and they are working as expected.
TEST_F(AudioRendererMixerManagerTest, CreateInputWithSessionId)
{
    // Expect AudioRendererMixerManager to call Start and Stop on our mock twice
    // each: for kDefaultDeviceId and for kAnotherDeviceId. Note: Under normal
    // conditions, each mixer would get its own sink!
    EXPECT_CALL(*mock_sink_.get(), Start()).Times(2);
    EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2);

    // Expect AudioRendererMixerManager to call Start and Stop on the matched sink
    // once.
    EXPECT_CALL(*mock_sink_matched_device_.get(), Start()).Times(1);
    EXPECT_CALL(*mock_sink_matched_device_.get(), Stop()).Times(1);

    // We expect 3 mixers to be created; each of them should release a sink.
    EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(2);
    EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_matched_device_.get())).Times(1);

    media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
        kChannelLayout, kSampleRate, kBitsPerChannel,
        kBufferSize);
    media::FakeAudioRenderCallback callback(0, kSampleRate);
    EXPECT_EQ(0, mixer_count());

    // Empty device id, zero session id;
    scoped_refptr<media::AudioRendererMixerInput> input_to_default_device(
        manager_->CreateInput(kRenderFrameId, 0, // session_id
            std::string(), kSecurityOrigin,
            AudioLatency::LATENCY_PLAYBACK));
    input_to_default_device->Initialize(params, &callback);
    EXPECT_EQ(0, mixer_count());

    // Specific device id, zero session id;
    scoped_refptr<media::AudioRendererMixerInput> input_to_matched_device(
        manager_->CreateInput(kRenderFrameId, 0, // session_id
            kMatchedDeviceId, kSecurityOrigin,
            AudioLatency::LATENCY_PLAYBACK));
    input_to_matched_device->Initialize(params, &callback);
    EXPECT_EQ(0, mixer_count());

    // Specific device id, non-zero session id (to be ignored);
    scoped_refptr<media::AudioRendererMixerInput> input_to_another_device(
        manager_->CreateInput(kRenderFrameId, 1, // session id
            kAnotherDeviceId, kSecurityOrigin,
            AudioLatency::LATENCY_PLAYBACK));
    input_to_another_device->Initialize(params, &callback);
    EXPECT_EQ(0, mixer_count());

    // Empty device id, non-zero session id;
    scoped_refptr<media::AudioRendererMixerInput>
        input_to_matched_device_with_session_id(manager_->CreateInput(
            kRenderFrameId, 2, // session id
            std::string(), kSecurityOrigin, AudioLatency::LATENCY_PLAYBACK));
    input_to_matched_device_with_session_id->Initialize(params, &callback);
    EXPECT_EQ(0, mixer_count());

    // Implicitly test that AudioRendererMixerInput was provided with the expected
    // callbacks needed to acquire an AudioRendererMixer and return it.
    input_to_default_device->Start();
    EXPECT_EQ(1, mixer_count());

    input_to_another_device->Start();
    EXPECT_EQ(2, mixer_count());

    input_to_matched_device->Start();
    EXPECT_EQ(3, mixer_count());

    // Should go to the same device as the input above.
    input_to_matched_device_with_session_id->Start();
    EXPECT_EQ(3, mixer_count());

    // Destroying the inputs should destroy the mixers.
    input_to_default_device->Stop();
    input_to_default_device = nullptr;
    EXPECT_EQ(2, mixer_count());
    input_to_another_device->Stop();
    input_to_another_device = nullptr;
    EXPECT_EQ(1, mixer_count());
    input_to_matched_device->Stop();
    input_to_matched_device = nullptr;
    EXPECT_EQ(1, mixer_count());
    input_to_matched_device_with_session_id->Stop();
    input_to_matched_device_with_session_id = nullptr;
    EXPECT_EQ(0, mixer_count());
}

// Verify GetMixer() correctly creates different mixers with the same
// parameters, but different device ID and/or security origin
TEST_F(AudioRendererMixerManagerTest, MixerDevices)
{
    EXPECT_CALL(*mock_sink_.get(), Start()).Times(3);
    EXPECT_CALL(*mock_sink_.get(), Stop()).Times(3);
    EXPECT_EQ(0, mixer_count());

    // We expect 3 mixers to be created; each of them should release a sink.
    EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(3);

    media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
        kChannelLayout, kSampleRate, kBitsPerChannel,
        kBufferSize);
    media::AudioRendererMixer* mixer1 = GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
        kDefaultDeviceId, kSecurityOrigin, nullptr);
    ASSERT_TRUE(mixer1);
    EXPECT_EQ(1, mixer_count());

    media::AudioRendererMixer* mixer2 = GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
        kAnotherDeviceId, kSecurityOrigin, nullptr);
    ASSERT_TRUE(mixer2);
    EXPECT_EQ(2, mixer_count());
    EXPECT_NE(mixer1, mixer2);

    media::AudioRendererMixer* mixer3 = GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
        kAnotherDeviceId, kSecurityOrigin2, nullptr);
    ASSERT_TRUE(mixer3);
    EXPECT_EQ(3, mixer_count());
    EXPECT_NE(mixer1, mixer3);
    EXPECT_NE(mixer2, mixer3);

    ReturnMixer(mixer1);
    EXPECT_EQ(2, mixer_count());
    ReturnMixer(mixer2);
    EXPECT_EQ(1, mixer_count());
    ReturnMixer(mixer3);
    EXPECT_EQ(0, mixer_count());
}

// Verify GetMixer() correctly deduplicate mixers with the same
// parameters, different security origins but default device ID
TEST_F(AudioRendererMixerManagerTest, OneMixerDifferentOriginsDefaultDevice)
{
    EXPECT_CALL(*mock_sink_.get(), Start()).Times(1);
    EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1);
    EXPECT_EQ(0, mixer_count());

    // We expect 1 mixer to be created; it should release its sink.
    EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(1);

    media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
        kChannelLayout, kSampleRate, kBitsPerChannel,
        kBufferSize);
    media::AudioRendererMixer* mixer1 = GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
        kDefaultDeviceId, kSecurityOrigin, nullptr);
    ASSERT_TRUE(mixer1);
    EXPECT_EQ(1, mixer_count());

    media::AudioRendererMixer* mixer2 = GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
        std::string(), kSecurityOrigin, nullptr);
    ASSERT_TRUE(mixer2);
    EXPECT_EQ(1, mixer_count());
    EXPECT_EQ(mixer1, mixer2);

    media::AudioRendererMixer* mixer3 = GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
        kDefaultDeviceId, kSecurityOrigin2, nullptr);
    ASSERT_TRUE(mixer3);
    EXPECT_EQ(1, mixer_count());
    EXPECT_EQ(mixer1, mixer3);

    media::AudioRendererMixer* mixer4 = GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
        std::string(), kSecurityOrigin2, nullptr);
    ASSERT_TRUE(mixer4);
    EXPECT_EQ(1, mixer_count());
    EXPECT_EQ(mixer1, mixer4);

    ReturnMixer(mixer1);
    EXPECT_EQ(1, mixer_count());
    ReturnMixer(mixer2);
    EXPECT_EQ(1, mixer_count());
    ReturnMixer(mixer3);
    EXPECT_EQ(1, mixer_count());
    ReturnMixer(mixer4);
    EXPECT_EQ(0, mixer_count());
}

// Verify that GetMixer() correctly returns a null mixer and an appropriate
// status code when a nonexistent device is requested.
TEST_F(AudioRendererMixerManagerTest, NonexistentDevice)
{
    EXPECT_EQ(0, mixer_count());

    // Mixer manager should release a not-ok sink when failing to create a mixer.
    EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_no_device_.get())).Times(1);

    media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
        kChannelLayout, kSampleRate, kBitsPerChannel,
        kBufferSize);
    media::OutputDeviceStatus device_status = media::OUTPUT_DEVICE_STATUS_OK;

    media::AudioRendererMixer* mixer = GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
        kNonexistentDeviceId, kSecurityOrigin, &device_status);

    EXPECT_FALSE(mixer);
    EXPECT_EQ(media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND, device_status);
    EXPECT_EQ(0, mixer_count());
}

// Verify GetMixer() correctly deduplicate mixers basing on latency
// requirements.
TEST_F(AudioRendererMixerManagerTest, LatencyMixing)
{
    EXPECT_CALL(*mock_sink_.get(), Start()).Times(3);
    EXPECT_CALL(*mock_sink_.get(), Stop()).Times(3);
    EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(3);

    EXPECT_EQ(0, mixer_count());

    media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
        kChannelLayout, kSampleRate, kBitsPerChannel,
        kBufferSize);
    media::AudioRendererMixer* mixer1 = GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
        kDefaultDeviceId, kSecurityOrigin, nullptr);
    ASSERT_TRUE(mixer1);
    EXPECT_EQ(1, mixer_count());

    media::AudioRendererMixer* mixer2 = GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
        kDefaultDeviceId, kSecurityOrigin, nullptr);
    ASSERT_TRUE(mixer2);
    EXPECT_EQ(mixer1, mixer2); // Same latency => same mixer.
    EXPECT_EQ(1, mixer_count());

    media::AudioRendererMixer* mixer3 = GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_RTC,
        kDefaultDeviceId, kSecurityOrigin, nullptr);
    ASSERT_TRUE(mixer3);
    EXPECT_NE(mixer1, mixer3);
    EXPECT_EQ(2, mixer_count()); // Another latency => another mixer.

    media::AudioRendererMixer* mixer4 = GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_RTC,
        kDefaultDeviceId, kSecurityOrigin, nullptr);
    EXPECT_EQ(mixer3, mixer4);
    EXPECT_EQ(2, mixer_count()); // Same latency => same mixer.

    media::AudioRendererMixer* mixer5 = GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_INTERACTIVE,
        kDefaultDeviceId, kSecurityOrigin, nullptr);
    ASSERT_TRUE(mixer5);
    EXPECT_EQ(3, mixer_count()); // Another latency => another mixer.

    media::AudioRendererMixer* mixer6 = GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_INTERACTIVE,
        kDefaultDeviceId, kSecurityOrigin, nullptr);
    EXPECT_EQ(mixer5, mixer6);
    EXPECT_EQ(3, mixer_count()); // Same latency => same mixer.

    ReturnMixer(mixer1);
    EXPECT_EQ(3, mixer_count());
    ReturnMixer(mixer2);
    EXPECT_EQ(2, mixer_count());
    ReturnMixer(mixer3);
    EXPECT_EQ(2, mixer_count());
    ReturnMixer(mixer4);
    EXPECT_EQ(1, mixer_count());
    ReturnMixer(mixer5);
    EXPECT_EQ(1, mixer_count());
    ReturnMixer(mixer6);
    EXPECT_EQ(0, mixer_count());
}

// Verify output bufer size of the mixer is correctly adjusted for Playback
// latency.
TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyPlayback)
{
    // Expecting hardware buffer size of 128 frames
    EXPECT_EQ(44100,
        mock_sink_->GetOutputDeviceInfo().output_params().sample_rate());
    // Expecting hardware buffer size of 128 frames
    EXPECT_EQ(
        128,
        mock_sink_->GetOutputDeviceInfo().output_params().frames_per_buffer());

    EXPECT_CALL(*mock_sink_.get(), Start()).Times(1);
    EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1);
    EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(1);

    media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
        kChannelLayout, 32000, kBitsPerChannel, 512);

    media::AudioRendererMixer* mixer = GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
        kDefaultDeviceId, kSecurityOrigin, nullptr);

#if defined(OS_CHROMEOS)
    // Expecting input sample rate
    EXPECT_EQ(32000, mixer->GetOutputParamsForTesting().sample_rate());
    // Round up 20 ms (640) to the power of 2.
    EXPECT_EQ(1024, mixer->GetOutputParamsForTesting().frames_per_buffer());

#else
    // Expecting hardware sample rate
    EXPECT_EQ(44100, mixer->GetOutputParamsForTesting().sample_rate());

// 20 ms at 44100 is 882 frames per buffer.
#if defined(OS_WIN)
    // Round up 882 to the nearest multiple of the output buffer size (128). which
    // is 7 * 128 = 896
    EXPECT_EQ(896, mixer->GetOutputParamsForTesting().frames_per_buffer());
#else
    // Round up 882 to the power of 2.
    EXPECT_EQ(1024, mixer->GetOutputParamsForTesting().frames_per_buffer());
#endif // defined(OS_WIN)

#endif // defined(OS_CHROMEOS)

    ReturnMixer(mixer);
}

// Verify output bufer size of the mixer is correctly adjusted for Playback
// latency when the device buffer size exceeds 20 ms.
TEST_F(AudioRendererMixerManagerTest,
    MixerParamsLatencyPlaybackLargeDeviceBufferSize)
{
    mock_sink_ = new media::MockAudioRendererSink(
        std::string(), media::OUTPUT_DEVICE_STATUS_OK,
        AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, 44100,
            kBitsPerChannel, 2048));

    EXPECT_CALL(*mock_sink_.get(), Start()).Times(1);
    EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1);
    EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(1);

    media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
        kChannelLayout, 32000, kBitsPerChannel, 512);

    media::AudioRendererMixer* mixer = GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
        kDefaultDeviceId, kSecurityOrigin, nullptr);

// 20 ms at 44100 is 882 frames per buffer.
#if defined(OS_CHROMEOS)
    // Expecting input sample rate
    EXPECT_EQ(32000, mixer->GetOutputParamsForTesting().sample_rate());
    // Ignore device buffer size, round up 20 ms (640) to the power of 2.
    EXPECT_EQ(1024, mixer->GetOutputParamsForTesting().frames_per_buffer());
#else
    // Expecting hardware sample rate
    EXPECT_EQ(44100, mixer->GetOutputParamsForTesting().sample_rate());
    // Prefer device buffer size (2048) if is larger than 20 ms buffer size (882).
    EXPECT_EQ(2048, mixer->GetOutputParamsForTesting().frames_per_buffer());
#endif

    ReturnMixer(mixer);
}

// Verify output bufer size of the mixer is correctly adjusted for Playback
// latency when output audio is fake.
TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyPlaybackFakeAudio)
{
    mock_sink_ = new media::MockAudioRendererSink(
        std::string(), media::OUTPUT_DEVICE_STATUS_OK,
        AudioParameters(AudioParameters::AUDIO_FAKE, kChannelLayout, 44100,
            kBitsPerChannel, 2048));

    EXPECT_CALL(*mock_sink_.get(), Start()).Times(1);
    EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1);
    EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(1);

    media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
        kChannelLayout, 32000, kBitsPerChannel, 512);

    media::AudioRendererMixer* mixer = GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
        kDefaultDeviceId, kSecurityOrigin, nullptr);

    // Expecting input sample rate
    EXPECT_EQ(32000, mixer->GetOutputParamsForTesting().sample_rate());

// 20 ms at 32000 is 640 frames per buffer.
#if defined(OS_WIN)
    // Use 20 ms buffer.
    EXPECT_EQ(640, mixer->GetOutputParamsForTesting().frames_per_buffer());
#else
    // Ignore device buffer size, round up 640 to the power of 2.
    EXPECT_EQ(1024, mixer->GetOutputParamsForTesting().frames_per_buffer());
#endif // defined(OS_WIN)

    ReturnMixer(mixer);
}

// Verify output bufer size of the mixer is correctly adjusted for RTC latency.
TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyRtc)
{
    // Expecting hardware buffer size of 128 frames
    EXPECT_EQ(44100,
        mock_sink_->GetOutputDeviceInfo().output_params().sample_rate());
    // Expecting hardware buffer size of 128 frames
    EXPECT_EQ(
        128,
        mock_sink_->GetOutputDeviceInfo().output_params().frames_per_buffer());

    EXPECT_CALL(*mock_sink_.get(), Start()).Times(1);
    EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1);
    EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(1);

    media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
        kChannelLayout, 32000, kBitsPerChannel, 512);

    media::AudioRendererMixer* mixer = GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_RTC,
        kDefaultDeviceId, kSecurityOrigin, nullptr);

#if defined(OS_CHROMEOS)
    int output_sample_rate = 32000;
#else
    // Expecting hardware sample rate.
    int output_sample_rate = 44100;
#endif // defined(OS_CHROMEOS)

    EXPECT_EQ(output_sample_rate,
        mixer->GetOutputParamsForTesting().sample_rate());

#if defined(OS_LINUX) || defined(OS_MACOSX)
    // Use 10 ms buffer (441 frames per buffer).
    EXPECT_EQ(output_sample_rate / 100,
        mixer->GetOutputParamsForTesting().frames_per_buffer());
#elif defined(OS_ANDROID)
    // If hardware buffer size (128) is less than 20 ms (882), use 20 ms buffer
    // (otherwise, use hardware buffer).
    EXPECT_EQ(882, mixer->GetOutputParamsForTesting().frames_per_buffer());
#else
    // Use hardware buffer size (128).
    EXPECT_EQ(128, mixer->GetOutputParamsForTesting().frames_per_buffer());
#endif // defined(OS_LINUX) || defined(OS_MACOSX)

    ReturnMixer(mixer);
}

// Verify output bufer size of the mixer is correctly adjusted for RTC latency
// when output audio is fake.
TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyRtcFakeAudio)
{
    mock_sink_ = new media::MockAudioRendererSink(
        std::string(), media::OUTPUT_DEVICE_STATUS_OK,
        AudioParameters(AudioParameters::AUDIO_FAKE, kChannelLayout, 44100,
            kBitsPerChannel, 128));

    EXPECT_CALL(*mock_sink_.get(), Start()).Times(1);
    EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1);
    EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(1);

    media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
        kChannelLayout, 32000, kBitsPerChannel, 512);

    media::AudioRendererMixer* mixer = GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_RTC,
        kDefaultDeviceId, kSecurityOrigin, nullptr);

    // Expecting input sample rate.
    EXPECT_EQ(32000, mixer->GetOutputParamsForTesting().sample_rate());

    // 10 ms at 32000 is 320 frames per buffer. Expect it on all the platforms for
    // fake audio output.
    EXPECT_EQ(320, mixer->GetOutputParamsForTesting().frames_per_buffer());

    ReturnMixer(mixer);
}

// Verify output bufer size of the mixer is correctly adjusted for Interactive
// latency.
TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyInteractive)
{
    // Expecting hardware buffer size of 128 frames
    EXPECT_EQ(44100,
        mock_sink_->GetOutputDeviceInfo().output_params().sample_rate());
    // Expecting hardware buffer size of 128 frames
    EXPECT_EQ(
        128,
        mock_sink_->GetOutputDeviceInfo().output_params().frames_per_buffer());

    EXPECT_CALL(*mock_sink_.get(), Start()).Times(1);
    EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1);
    EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(1);

    media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
        kChannelLayout, 32000, kBitsPerChannel, 512);

    media::AudioRendererMixer* mixer = GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_INTERACTIVE,
        kDefaultDeviceId, kSecurityOrigin, nullptr);

#if defined(OS_CHROMEOS)
    // Expecting input sample rate.
    EXPECT_EQ(32000, mixer->GetOutputParamsForTesting().sample_rate());
#else
    // Expecting hardware sample rate.
    EXPECT_EQ(44100, mixer->GetOutputParamsForTesting().sample_rate());
#endif // defined(OS_CHROMEOS)

#if defined(OS_ANDROID)
    // If hardware buffer size (128) is less than 1024, use 2048.
    EXPECT_EQ(2048, mixer->GetOutputParamsForTesting().frames_per_buffer());
#else
    // Expect hardware buffer size.
    EXPECT_EQ(128, mixer->GetOutputParamsForTesting().frames_per_buffer());
#endif

    ReturnMixer(mixer);
}

} // namespace content
